import derbyos
import zmq
from derbyos import DerbyXML
from derbyos import Stopwatch
from derbyos import NSOde
from derbyos import BoutStates
import wx
import wxDerbyOS
# need to use wx events to move updates from stopwatch to main event loop        
from wxDerbyOS import UpdateOnMainThread, Stopwatcher


class TreeInspector(wx.Frame):
    def __init__(self, nsode):
        import keyword

        self.nsode = nsode
        super(TreeInspector, self).__init__(None, title="Tree Inspector", size=(400, 500))
        grid = wx.FlexGridSizer(wx.VERTICAL, 1, 2)
        self.state_label = wx.StaticText(self, label="State:")
        self.tree_ctrl = wx.TreeCtrl(self, -1, style=wx.TR_DEFAULT_STYLE |
                                                     wx.TR_FULL_ROW_HIGHLIGHT |
                                                     wx.TR_EDIT_LABELS, size=(400, 500))
        grid.Add(self.state_label, 0, wx.EXPAND)
        grid.Add(self.tree_ctrl, 1, wx.EXPAND)
        self.SetSizer(grid)
        self.SetAutoLayout(1)
        grid.Fit(self)
        # Add the tree root
        self.root = self.tree_ctrl.AddRoot('DerbyXML')
        self.tree_ctrl.SetItemData(self.root, wx.TreeItemData(self.nsode.derbyXML))
        self.updateXMLTree(self.root, True)
        self.tree_ctrl.ExpandAll()
        self.Centre()

        def updatetree(nodes):
            print "Update tree", nodes
            for node in nodes:
                self.updateXMLTreeNode(self.itemForNode(node))

        self.nsode.AddWatcher("*", updatetree)

        def StateChanged(obj, name, value):
            #print "@@@State",value
            self.state_label.SetLabelText("State:" + BoutStates.BoutStateStrings[value])

        self.nsode.boutState.addObserver(UpdateOnMainThread(self, StateChanged), "boutState")

    def itemForNode(self, xml, parent=None):
        if parent is None:
            parent = self.root
        if xml == self.tree_ctrl.GetItemData(parent):
            return parent
        child, cookie = self.tree_ctrl.GetFirstChild(parent)
        while child.IsOk():
            retval = self.itemForNode(xml, child)
            if retval is not None:
                return retval
            child, cookie = self.tree_ctrl.GetNextChild(child, cookie)
        return None

    def allChildrenOfItem(self, parent):
        retval = []
        child, cookie = self.tree_ctrl.GetFirstChild(parent)
        while child.IsOk():
            retval.append(child)
            child, cookie = self.tree_ctrl.GetNextChild(child, cookie)
        return retval

    def treeTextForNode(self, xml):
        text = "<" + xml.elementName
        attr = xml.attributes
        for tag in attr:
            if attr[tag] is not None:
                text = text + " " + tag + "=\"" + str(attr[tag]) + "\""
        if xml.text:
            text = text + ">" + xml.text + "</" + xml.elementName + ">"
        else:
            text += "/>"
        return text

    def updateXMLTree(self, item, deep=False):
        self.tree_ctrl.DeleteChildren(item)
        xml = self.tree_ctrl.GetItemData(item).Data
        self.tree_ctrl.SetItemText(item, self.treeTextForNode(xml))
        for child in xml.children:
            subitem = self.tree_ctrl.AppendItem(item, self.treeTextForNode(child))
            self.tree_ctrl.SetItemData(subitem, wx.TreeItemData(child))
            if deep:
                self.updateXMLTree(subitem, deep)

    def notYetUpdateXMLTree(self, item, deep=False):
        oldChildren = self.allChildrenOfItem(item)
        xml = self.tree_ctrl.GetItemData(item).Data
        self.tree_ctrl.SetItemText(item, self.treeTextForNode(xml))
        for child in xml.children:
            oldItem = None
            for old in oldChildren:
                if self.tree_ctrl.GetItemData(old).Data == child:
                    oldItem = old
                    break
            if oldItem:  # this item was already in the parent, just update it
                subitem = oldItem
                print "Tree Updating old child", self.tree_ctrl.GetItemText(oldItem)
                self.tree_ctrl.SetItemText(subitem, self.treeTextForNode(child))
                oldChildren.remove(oldItem)
            else:
                print "Tree Adding new child", self.treeTextForNode(child)
                subitem = self.tree_ctrl.AppendItem(item, self.treeTextForNode(child))
                self.tree_ctrl.SetItemData(subitem, wx.TreeItemData(child))
            if deep:
                self.updateXMLTree(subitem, deep)
        # remove anything old child we no longer have
        for old in oldChildren:
            print "Tree Removing old child", self.tree_ctrl.GetItemText(old)
            self.tree_ctrl.Delete(old)

    def updateXMLTreeNode(self, node):
        self.updateXMLTree(self.root, True)


if __name__ == '__main__':
    wxDerbyOS.testWX("Tree Inspector", TreeInspector)
